#include "PtrManager.h"
#include "Logger.h"
#include <Rz/String.h>

#include <map>

#ifdef RZ_INCLUDE_PTRMANAGER

namespace Rz { namespace Diagnostics {

struct InternalType
{
	const IObject* ObjPtr;
	Rz::String TypeName;

	InternalType(const IObject* obj) : ObjPtr(obj), TypeName(obj->GetTypeInfo()->GetClassName()) { }

	bool operator == (const InternalType& r) { return r.ObjPtr == ObjPtr; }
	friend bool operator < (const InternalType& l, const InternalType& r) { return l.ObjPtr < r.ObjPtr; }
};

std::map<InternalType, u32> _ptrMap;

PtrManager::PtrManager()
	: _stream(stderr)
	, _options(Options::LogAll)
	, _paused(false)
{

}

PtrManager::~PtrManager()
{

}

void PtrManager::AddReference(const IObject* obj)
{
	_ptrMap[obj]++;

	if (!!(_options & Options::LogReferenceAdd) && !_paused)
	{
		RZ_LOG("[+] 0x%p:'%s' (%i)", obj, obj->GetTypeInfo()->GetClassName(), _ptrMap[obj]);
	}
}


void PtrManager::RemoveReference(const IObject* obj)
{
	_ptrMap[obj]--;

	if (!!(_options & Options::LogReferenceRemove) && !_paused)
	{
		RZ_LOG("[-] 0x%p:'%s' (%i)", obj, obj->GetTypeInfo()->GetClassName(), _ptrMap[obj]);
	}

	if (_ptrMap[obj] <= 0)
	{
		_ptrMap.erase(_ptrMap.find(obj));
	}
}


void PtrManager::PrintMemoryMap() const
{
	RZ_LOG("+++++++++++++++++++++ memory map begin +++++++++++++++++++++", "");

	for (auto& e : _ptrMap)
	{
		RZ_LOG("[*] 0x%p:'%s' (%i)", e.first.ObjPtr, e.first.TypeName.GetCharArray(), e.second);
	}

	RZ_LOG("+++++++++++++++++++++  memory map end  +++++++++++++++++++++", "");
}

void PtrManager::Pause(bool pause)
{
	_paused = pause;
}

void PtrManager::Resume()
{
	_paused = false;
}

} } 

#endif
